/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "driver/tsw/hpm6e00_tsw.h"

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief TSW 设置端口时钟延时
 *
 * @param port   设置的端口
 * @param tx_dly tx 时钟延迟线延时值
 * @param rx_dly rx 时钟延迟线延时值
 *
 * @return 成功返回 0
 */
int tsw_port_clk_delay_set(uint8_t port, uint8_t tx_dly, uint8_t rx_dly){
    if (port > TSW_TSNPORT_PORT3) {
        return -EINVAL;
    }

    HPM_TSW->TSNPORT[port].GPR_CTRL0 &= ~(TSW_TSNPORT_GPR_CTRL0_TXCLK_DLY_SEL_MASK |
            TSW_TSNPORT_GPR_CTRL0_RXCLK_DLY_SEL_MASK);
    HPM_TSW->TSNPORT[port].GPR_CTRL0 |= TSW_TSNPORT_GPR_CTRL0_TXCLK_DLY_SEL_SET(tx_dly) |
            TSW_TSNPORT_GPR_CTRL0_RXCLK_DLY_SEL_SET(rx_dly);

    return 0;
}

void tsw_rtc_time_increment_set(uint32_t increment){
    HPM_TSW->TSNPORT[TSW_TSNPORT_PORT1].RTC_CT_TIMER_INCR = increment;
}

/**
 * \brief TSW 使能 MAC 控制
 *
 * @param port     设置的端口
 * @param mac_type MAC 类型
 *
 * @return 成功返回 0
 */
int tsw_ep_mac_ctrl_enable(uint8_t port, tsw_mac_type_t mac_type){
    uint32_t temp;

    if (port > TSW_TSNPORT_PORT3) {
        return -EINVAL;
    }

    temp = HPM_TSW->TSNPORT[port].MAC[mac_type].MAC_MAC_CTRL;
    temp |= TSW_TSNPORT_MAC_MAC_MAC_CTRL_TX_EN_MASK | TSW_TSNPORT_MAC_MAC_MAC_CTRL_RX_EN_MASK;
    HPM_TSW->TSNPORT[port].MAC[mac_type].MAC_MAC_CTRL = temp;

    return 0;
}

/**
 * \brief TSW 关闭 MAC 控制
 *
 * @param port     设置的端口
 * @param mac_type MAC 类型
 *
 * @return 成功返回 0
 */
int tsw_ep_mac_ctrl_disable(uint8_t        port,
                            tsw_mac_type_t mac_type){
    uint32_t temp;

    if (port > TSW_TSNPORT_PORT3) {
        return -EINVAL;
    }

    temp = HPM_TSW->TSNPORT[port].MAC[mac_type].MAC_MAC_CTRL;
    temp &= ~(TSW_TSNPORT_MAC_MAC_MAC_CTRL_TX_EN_MASK | TSW_TSNPORT_MAC_MAC_MAC_CTRL_RX_EN_MASK);
    HPM_TSW->TSNPORT[port].MAC[mac_type].MAC_MAC_CTRL = temp;

    do {
        temp = HPM_TSW->TSNPORT[port].MAC[mac_type].MAC_MAC_CTRL;
    } while (TSW_TSNPORT_MAC_MAC_MAC_CTRL_RX_EN_GET(temp) || TSW_TSNPORT_MAC_MAC_MAC_CTRL_TX_EN_GET(temp));

    return 0;
}

/**
 * \brief TSW 使能所有 MAC 控制
 *
 * @param mac_type MAC 类型
 */
void tsw_ep_all_mac_ctrl_enable(tsw_mac_type_t mac_type){
    for (uint8_t i = 0; i <= TSW_TSNPORT_PORT3; i++) {
        tsw_ep_mac_ctrl_enable(i, mac_type);
    }
}

/**
 * \brief TSW 关闭所有 MAC 控制
 *
 * @param mac_type MAC 类型
 */
void tsw_ep_all_mac_ctrl_disable(tsw_mac_type_t mac_type){
    for (uint8_t i = 0; i <= TSW_TSNPORT_PORT3; i++) {
        tsw_ep_mac_ctrl_disable(i, mac_type);
    }
}

void tsw_cam_clear(void){
    HPM_TSW->LU_MAIN_HITMEM &= ~TSW_LU_MAIN_HITMEM_CAMMEMCLR_MASK;
    HPM_TSW->LU_MAIN_HITMEM |= TSW_LU_MAIN_HITMEM_CAMMEMCLR_MASK;
}


void tsw_cam_vlan_port_set(void){
    HPM_TSW->APB2AXI_CAM_REQDATA_1 = 0x0f;
    HPM_TSW->APB2AXI_CAM_REQDATA_0 = (1 << 16)  /* VID = 1 */
                               | (1 << 8)   /* 1: Set one VLAN_PORT entry */
                               | (1 << 0);  /* CAM APB2AXIS channel selection. Always 1 for writing to VLAN_PORT table. */
}

/**
 * \brief 设置 TSW 端口 MAC 模式
 *
 * @param port 设置的端口
 * @param mode MAC 地址
 *
 * @return 成功返回 0
 */
int tsw_ep_mac_mode_set(uint8_t port, tsw_mac_mode_t mode){
    uint32_t temp;

    if (port > TSW_TSNPORT_PORT3) {
        return -EINVAL;
    }

    /* MAC must be disabled when changing mode */
    temp = HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MAC_CTRL;
    if (TSW_TSNPORT_MAC_MAC_MAC_CTRL_RX_EN_GET(temp) || TSW_TSNPORT_MAC_MAC_MAC_CTRL_TX_EN_GET(temp)) {
        return -EPERM;
    }

    temp &= ~(TSW_TSNPORT_MAC_MAC_MAC_CTRL_CLKSEL_MASK | TSW_TSNPORT_MAC_MAC_MAC_CTRL_PHYSEL_MASK | TSW_TSNPORT_MAC_MAC_MAC_CTRL_GMIIMODE_MASK);
    temp &= ~TSW_TSNPORT_MAC_MAC_MAC_CTRL_RESSTAT_MASK;

    temp |= TSW_TSNPORT_MAC_MAC_MAC_CTRL_CLKSEL_SET(1)
         | TSW_TSNPORT_MAC_MAC_MAC_CTRL_PHYSEL_SET(1)
         | TSW_TSNPORT_MAC_MAC_MAC_CTRL_GMIIMODE_SET(mode);

    HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MAC_CTRL = temp;

    return 0;
}

/**
 * \brief 设置 TSW 端口 MAC 地址
 *
 * @param port       设置的端口
 * @param p_mac_addr MAC 地址
 * @param is_promisc 是否启用启用了混杂模式
 *
 * @return 成功返回 0
 */
int tsw_ep_mac_addr_set(uint8_t port, uint8_t *p_mac_addr, bool_t is_promisc){
    uint32_t temp;

    if ((port > TSW_TSNPORT_PORT3) || (p_mac_addr == NULL)) {
        return -EINVAL;
    }

    /* MAC must be disabled when changing mode */
    temp = HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MAC_CTRL;
    if (TSW_TSNPORT_MAC_MAC_MAC_CTRL_RX_EN_GET(temp) || TSW_TSNPORT_MAC_MAC_MAC_CTRL_TX_EN_GET(temp)) {
        return -EPERM;
    }

    HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MACADDR_L = MAC_LO(p_mac_addr);
    HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MACADDR_H = MAC_HI(p_mac_addr) | TSW_TSNPORT_MAC_MAC_MACADDR_H_PROMISC_SET(is_promisc);

    return 0;
}

/**
 * \brief TSW 端口接口设置
 *
 * @param port 相关端口
 * @param itf  接口模式
 *
 * @return 成功返回 0
 */
int tsw_port_interface_set(uint8_t port, tsw_port_phy_itf_t itf){
    if (port > TSW_TSNPORT_PORT3) {
        return -EINVAL;
    }

    HPM_TSW->TSNPORT[port].GPR_CTRL2 &= ~TSW_TSNPORT_GPR_CTRL2_PHY_INTF_SEL_MASK;
    HPM_TSW->TSNPORT[port].GPR_CTRL2 |= TSW_TSNPORT_GPR_CTRL2_PHY_INTF_SEL_SET(itf);

    return 0;
}

/**
 * \brief TSW 设置 MDIO 配置
 *
 * @param port    相关端口
 * @param clk_div 时钟分频
 *
 * @return 成功返回 0
 */
int tsw_ep_mdio_cfg_set(uint8_t port, uint8_t clk_div){
    if (port > TSW_TSNPORT_PORT3) {
        return -EINVAL;
    }

    HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MDIO_CFG = TSW_TSNPORT_MAC_MAC_MDIO_CFG_ENABLE_MASK | TSW_TSNPORT_MAC_MAC_MDIO_CFG_MDC_CLKDIV_SET(clk_div);

    return 0;
}

/**
 * \brief TSW MDIO 读函数
 *
 * @param port     相关端口
 * @param phy_addr PHY 设备地址
 * @param reg_addr PHY 设备要读的寄存器地址
 * @param p_data   存储读取的数据
 *
 * @return 成功返回 0
 */
int tsw_ep_mdio_read(uint8_t   port,
                     uint32_t  phy_addr,
                     uint32_t  reg_addr,
                     uint16_t *p_data){
    uint32_t time_out = 50000;

    if ((port > TSW_TSNPORT_PORT3) || (p_data == NULL)) {
        return -EINVAL;
    }

    HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MDIO_CTRL = TSW_TSNPORT_MAC_MAC_MDIO_CTRL_OP_SET(MAC_MDIO_CTRL_OP_RD)
                                                        | TSW_TSNPORT_MAC_MAC_MDIO_CTRL_PHYAD_SET(phy_addr)
                                                        | TSW_TSNPORT_MAC_MAC_MDIO_CTRL_REGAD_SET(reg_addr)
                                                        | TSW_TSNPORT_MAC_MAC_MDIO_CTRL_INIT_SET(1);

    do {
        if ((--time_out) == 0) {
            return -ETIME;
        }
    } while (TSW_TSNPORT_MAC_MAC_MDIO_CTRL_READY_GET(HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MDIO_CTRL) == 0);

     *p_data = TSW_TSNPORT_MAC_MAC_MDIO_RD_DATA_RD_DATA_GET(HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MDIO_RD_DATA);

    return 0;
}

/**
 * \brief TSW MDIO 写函数
 *
 * @param port     相关端口
 * @param phy_addr PHY 设备地址
 * @param reg_addr PHY 设备要写的寄存器地址
 * @param data     要写的数据
 *
 * @return 成功返回 0
 */
int tsw_ep_mdio_write(uint8_t  port,
                      uint32_t phy_addr,
                      uint32_t reg_addr,
                      uint16_t data){
    uint32_t time_out = 50000;

    HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MDIO_WR_DATA = data;
    HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MDIO_CTRL = TSW_TSNPORT_MAC_MAC_MDIO_CTRL_OP_SET(MAC_MDIO_CTRL_OP_WR)
                                                        | TSW_TSNPORT_MAC_MAC_MDIO_CTRL_PHYAD_SET(phy_addr)
                                                        | TSW_TSNPORT_MAC_MAC_MDIO_CTRL_REGAD_SET(reg_addr)
                                                        | TSW_TSNPORT_MAC_MAC_MDIO_CTRL_INIT_SET(1);

    do {
        if ((--time_out) == 0) {
            return -ETIME;
        }
    } while (TSW_TSNPORT_MAC_MAC_MDIO_CTRL_READY_GET(HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MDIO_CTRL) == 0);

    return 0;
}

/**
 * \brief TSW 获取默认的 DMA 配置
 *
 * @param p_config DMA 配置结构体
 */
void tsw_default_dma_cfg_get(struct tsw_dma_config *p_config){
    if (p_config) {
        p_config->soe    = 0;
        p_config->irq    = 0;
        p_config->maxlen = 0xff;
    }
}


/**
 * \brief TSW 发送初始化
 *
 * @param p_config DMA 配置结构体
 *
 * @return 成功返回 0
 */
int tsw_send_init(struct tsw_dma_config *p_config){
    uint32_t time_out = 50000;

    if (p_config == NULL) {
        return -EINVAL;
    }

    HPM_TSW->MM2S_DMA_CR |= TSW_MM2S_DMA_CR_RESET_MASK;

    do {
        if ((--time_out) == 0) {
            return -ETIME;
        }
    } while (TSW_MM2S_DMA_SR_RSET_GET(HPM_TSW->MM2S_DMA_SR));

    HPM_TSW->MM2S_DMA_CR &= ~TSW_MM2S_DMA_CR_SOE_MASK;
    HPM_TSW->MM2S_DMA_CR |= TSW_MM2S_DMA_CR_SOE_SET(p_config->soe);

    HPM_TSW->MM2S_DMA_CR &= ~TSW_MM2S_DMA_CR_MXLEN_MASK;
    HPM_TSW->MM2S_DMA_CR |= TSW_MM2S_DMA_CR_MXLEN_SET(p_config->maxlen);

    HPM_TSW->MM2S_DMA_CR &= ~TSW_MM2S_DMA_CR_IRQEN_MASK;
    HPM_TSW->MM2S_DMA_CR |= TSW_MM2S_DMA_CR_IRQEN_SET(p_config->irq);

    HPM_TSW->MM2S_DMA_CR |= TSW_MM2S_DMA_CR_RUN_MASK;

    return 0;
}

/**
 * \brief TSW 接收初始化
 *
 * @param p_config DMA 配置结构体
 *
 * @return 成功返回 0
 */
int tsw_recv_init(struct tsw_dma_config *p_config){
    uint32_t time_out = 50000;

    if (p_config == NULL) {
        return -EINVAL;
    }

    HPM_TSW->S2MM_DMA_CR |= TSW_S2MM_DMA_CR_RESET_MASK;

    do {
        if ((--time_out) == 0) {
            return -ETIME;
        }
    } while (TSW_S2MM_DMA_SR_RSET_GET(HPM_TSW->S2MM_DMA_SR));

    HPM_TSW->S2MM_DMA_CR &= ~TSW_S2MM_DMA_CR_SOE_MASK;
    HPM_TSW->S2MM_DMA_CR |= TSW_S2MM_DMA_CR_SOE_SET(p_config->soe);

    HPM_TSW->S2MM_DMA_CR &= ~TSW_S2MM_DMA_CR_MXLEN_MASK;
    HPM_TSW->S2MM_DMA_CR |= TSW_S2MM_DMA_CR_MXLEN_SET(p_config->maxlen);

    HPM_TSW->S2MM_DMA_CR &= ~TSW_S2MM_DMA_CR_IRQEN_MASK;
    HPM_TSW->S2MM_DMA_CR |= TSW_S2MM_DMA_CR_IRQEN_SET(p_config->irq);

    HPM_TSW->S2MM_DMA_CR |= TSW_S2MM_DMA_CR_RUN_MASK;

    return 0;
}

/**
 * \brief 设置发送帧
 */
static int __send_frame_setup(uint8_t *p_buf, uint16_t buf_len, uint8_t id){
    uint32_t timeout;

    /* set timeout */
    timeout = TSW_MM2S_DMA_WAIT_CBUFF_TIMEOUT;

    /* make sure that CBUFF is not full */
    do {

    } while (TSW_MM2S_DMA_SR_CBUFF_GET(HPM_TSW->MM2S_DMA_SR) && --timeout);

    if (timeout == 0) {
        return -ETIME;
    }

    /* 设置 ADDRL */
    HPM_TSW->MM2S_ADDRLO = (uint32_t)p_buf;

    /* 设置 Length */
    HPM_TSW->MM2S_LENGTH = buf_len;

    /* 设置 Ctrl */
    HPM_TSW->MM2S_CTRL = TSW_MM2S_CTRL_GO_MASK | TSW_MM2S_CTRL_ID_SET(id);

    return 0;
}

/**
 * \brief TSW 帧发送函数
 *
 * @param p_buf   要发送的缓存
 * @param buf_len 要发送的缓存长度
 * @param id      DMA 通道 ID
 *
 * @return 成功返回 0
 */
int tsw_frame_send(uint8_t *p_buf, uint16_t buf_len, uint8_t id){

    if ((p_buf == NULL) || (buf_len == 0) || (id > 15)) {
        return -EINVAL;
    }

    /* 设置发送缓存 */
    __send_frame_setup(p_buf, buf_len, id);

    /* 获取相应 */
    HPM_TSW->MM2S_RESP;

    return 0;
}

/**
 * \brief TSW 帧发送并且检查响应函数
 *
 * @param p_buf   要发送的缓存
 * @param buf_len 要发送的缓存长度
 * @param id      DMA 通道 ID
 *
 * @return 成功返回 0
 */
int tsw_frame_send_chk_resp(uint8_t *p_buf, uint16_t buf_len, uint8_t id){
    uint32_t timeout;
    uint32_t resp;

    if ((p_buf == NULL) || (buf_len == 0) || (id > 15)) {
        return -EINVAL;
    }

    /* 设置发送缓存 */
    __send_frame_setup(p_buf, buf_len, id);

    /* 设置超时时间 */
    timeout = TSW_MM2S_DMA_CHECK_RBUFE_TIMEOUT;

    /* 等待响应*/
    do {

    } while (TSW_MM2S_DMA_SR_RBUFE_GET(HPM_TSW->MM2S_DMA_SR) && --timeout);

    if (timeout == 0) {
        return -ETIME;
    }

    /* 获取响应 */
    resp = HPM_TSW->MM2S_RESP;

    if (TSW_MM2S_RESP_ID_GET(resp) == id) {
        /* 检查解码错误 */
        if (TSW_MM2S_RESP_DECERR_GET(resp)) {
            return -EPERM;
        }

        /* Check slave error */
        if (TSW_MM2S_RESP_SLVERR_GET(resp)) {
            return -EPERM;
        }
    } else {
        return -EPERM;
    }

    return 0;
}

/**
 * \brief TSW 提交接收描述
 *
 * @param p_buf   提交的接收缓存的地址
 * @param buf_len 提交的接收缓存的长度
 * @param id      绑定缓存的 DMA ID
 *
 * @return 成功返回 0
 */
int tsw_commit_recv_desc(uint8_t *p_buf, uint16_t buf_len, uint8_t id){

    if ((p_buf == NULL) || (buf_len == 0) || (id > 15)) {
        return -EINVAL;
    }

    /* 设置 ADDRL */
    HPM_TSW->S2MM_ADDRLO = (uint32_t)p_buf;

    /* 设置 Length */
    HPM_TSW->S2MM_LENGTH = buf_len;

    /* 设置 Ctrl */
    HPM_TSW->S2MM_CTRL &= ~TSW_S2MM_CTRL_ID_MASK;
    HPM_TSW->S2MM_CTRL |= TSW_S2MM_CTRL_GO_MASK | TSW_S2MM_CTRL_ID_SET(id);

    return 0;
}

/**
 * \brief TSW 帧接收函数
 *
 * @param p_frame TSW 帧结构体
 *
 * @return 成功返回 0
 */
int tsw_frame_recv(struct tsw_frame *p_frame){
    uint32_t resp;
    int      stat = -ETIME;

    if (TSW_S2MM_DMA_SR_IRQ_GET(HPM_TSW->S2MM_DMA_SR)) {

        resp = HPM_TSW->S2MM_RESP;

        p_frame->id  = TSW_S2MM_RESP_ID_GET(resp);
        p_frame->len = TSW_S2MM_RESP_LENGTH_GET(resp);

        if (TSW_S2MM_RESP_DECERR_GET(resp) || TSW_S2MM_RESP_SLVERR_GET(resp)) {
            stat = -EPERM;
        } else {
            stat = 0;
        }

        HPM_TSW->S2MM_DMA_SR = TSW_S2MM_DMA_SR_IRQ_MASK;
    }

    return stat;
}

static uint32_t tsw_ns_to_systicks(uint32_t nanoseconds, uint32_t busfreq)
{
    return (uint32_t)((uint64_t)nanoseconds * busfreq / TSW_NS_IN_ONE_SEC);
}

int tsw_shap_tas_controllist_set(uint8_t port, uint32_t index, struct tsw_tas_controllist_entry *p_entry)
{
    if (index >= TSW_SOC_SHAP_MAX_CL_ENTRIES) {
        return -EINVAL;
    }

    HPM_TSW->TSNPORT[port].SHACL[index].TSN_SHAPER_ACLIST_ENTRY_L = TSW_TSNPORT_SHACL_TSN_SHAPER_ACLIST_ENTRY_L_OP_SET(p_entry->op)
                                                               | TSW_TSNPORT_SHACL_TSN_SHAPER_ACLIST_ENTRY_L_STATE_SET(p_entry->state);
    HPM_TSW->TSNPORT[port].SHACL[index].TSN_SHAPER_ACLIST_ENTRY_H = TSW_TSNPORT_SHACL_TSN_SHAPER_ACLIST_ENTRY_H_TIME_SET(p_entry->interval);

    return 0;
}

int tsw_shap_tas_listlen_set(uint8_t port, uint32_t listlen)
{
    if (listlen > TSW_SOC_SHAP_MAX_CL_ENTRIES) {
        return -EINVAL;
    }

    HPM_TSW->TSNPORT[port].TSN_SHAPER_TAS_LISTLEN = TSW_TSNPORT_TSN_SHAPER_TAS_LISTLEN_ALISTLEN_SET(listlen);

    return 0;
}

int tsw_shap_tas_cycletime_set(uint8_t port, uint32_t cycle_time)
{
    HPM_TSW->TSNPORT[port].TSN_SHAPER_TAS_ACYCLETM  = TSW_TSNPORT_TSN_SHAPER_TAS_ACYCLETM_CTIME_SET(cycle_time);

    return 0;
}

int tsw_shap_tas_basetime_set(uint8_t port, uint32_t basetime_sec, uint32_t basetime_ns)
{
    HPM_TSW->TSNPORT[port].TSN_SHAPER_TAS_ABASETM_L = TSW_TSNPORT_TSN_SHAPER_TAS_ABASETM_L_BASETM_L_SET(basetime_ns);
    HPM_TSW->TSNPORT[port].TSN_SHAPER_TAS_ABASETM_H = TSW_TSNPORT_TSN_SHAPER_TAS_ABASETM_H_BASETM_H_SET(basetime_sec);

    return 0;
}

int tsw_shap_tas_change_config(uint8_t port)
{
    HPM_TSW->TSNPORT[port].TSN_SHAPER_TAS_CRSR |= TSW_TSNPORT_TSN_SHAPER_TAS_CRSR_CFGCHG_MASK;

    return 0;
}
int tsw_shap_tas_set(uint8_t port, struct tsw_tas_config *p_config){
    struct tsw_tas_controllist_entry entry;

    if ((port > TSW_TSNPORT_PORT3) ||
            (p_config == NULL) ||
            (p_config->entry_count == 0) ||
            (p_config->entry_count > TSW_SOC_SHAP_MAX_CL_ENTRIES)) {
        return -EINVAL;
    }

    for (uint32_t idx = 0; idx < p_config->entry_count; idx++, p_config->p_entry++) {
        entry.op        = p_config->p_entry->op;
        entry.state     = p_config->p_entry->state;
        entry.interval  = tsw_ns_to_systicks(p_config->p_entry->interval, TSW_BUS_FREQ);
        tsw_shap_tas_controllist_set(port, idx, &entry);
    }

    tsw_shap_tas_listlen_set(port, p_config->entry_count);
    tsw_shap_tas_cycletime_set(port, p_config->cycle_time); /* cycle length in nanoseconds */
    tsw_shap_tas_basetime_set(port, p_config->base_time_sec, p_config->base_time_ns);
    tsw_shap_tas_change_config(port);

    return 0;
}

int tsw_shap_enable_tas(uint8_t port)
{
    HPM_TSW->TSNPORT[port].TSN_SHAPER_TAS_CRSR |= TSW_TSNPORT_TSN_SHAPER_TAS_CRSR_EN_MASK;

    return 0;
}

int tsw_shap_get_tas_crsr(uint8_t port, uint32_t *crsr)
{
     *crsr = HPM_TSW->TSNPORT[port].TSN_SHAPER_TAS_CRSR;

     return 0;
}

void tsw_lookup_table_set(uint16_t entry_num, uint8_t dest_port, uint64_t dest_mac){

    /* Create a new ALMEM entry. This will specify what will be done with those detected frames */
    if (TSW_APB2AXIS_ALMEM_STS_RDY_GET(HPM_TSW->APB2AXIS_ALMEM_STS)) {

        HPM_TSW->APB2AXIS_ALMEM_REQDATA_1 = TSW_APB2AXIS_ALMEM_REQDATA_1_WR_NRD_SET(1) | TSW_APB2AXIS_ALMEM_REQDATA_1_ENTRY_NUM_SET(entry_num);

        /* set forward to destination port, use PCP field, UTAG 1 and trigger the interface for sending the data */
        HPM_TSW->APB2AXIS_ALMEM_REQDATA_0 = TSW_APB2AXIS_ALMEM_REQDATA_0_UTAG_SET(1) |
                                        TSW_APB2AXIS_ALMEM_REQDATA_0_QSEL_SET(0) |
                                        TSW_APB2AXIS_ALMEM_REQDATA_0_DROP_SET(0) |
                                        TSW_APB2AXIS_ALMEM_REQDATA_0_QUEUE_SET(0) |
                                        TSW_APB2AXIS_ALMEM_REQDATA_0_DEST_SET(dest_port);
    }

    HPM_TSW->APB2AXI_CAM_REQDATA_2 = TSW_APB2AXI_CAM_REQDATA_2_VID_SET(1) | TSW_APB2AXI_CAM_REQDATA_2_DESTMAC_HI_SET((dest_mac >> 32));
    HPM_TSW->APB2AXI_CAM_REQDATA_1 = TSW_APB2AXI_CAM_REQDATA_1_DESTMAC_LO_PORT_VEC_SET(dest_mac);
    HPM_TSW->APB2AXI_CAM_REQDATA_0 = TSW_APB2AXI_CAM_REQDATA_0_ENTRY_NUM_SET(entry_num) |
                                 TSW_APB2AXI_CAM_REQDATA_0_TYPE_SET(1) |   /* Set one DEST_MAC/VLAN_ID entry */
                                 TSW_APB2AXI_CAM_REQDATA_0_CH_SET(0);      /* CAM APB2AXIS channel selection. Always 0 for writing to DEST_MAC/VLAN_ID */

}
